package com.shopx.auth.service.impl;

import com.shopx.auth.DTO.LoginUserDTO;
import com.shopx.auth.dao.db1.SysUserRoleDao;
import com.shopx.auth.model.SysUrlModel;
import com.shopx.auth.model.SysUserRoleModel;
import com.shopx.auth.service.ICheckAuthService;
import com.shopx.auth.service.ISysLoginTokenService;
import com.shopx.auth.service.ISysUrlService;
import com.shopx.base.constants.ResultCodeEnum;
import com.shopx.base.exception.ShopxException;
import com.shopx.core.common.CommonConstant;
import com.shopx.core.utils.RSAUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.util.List;

@Slf4j
@Service
public class CheckAuthServiceImpl implements ICheckAuthService {

  @Autowired
  private ISysUrlService urlService;

  @Autowired
  private SysUserRoleDao sysUserRoleDao;

  @Value("${key.rsaPrivateKey:}")
  private String rsaPrivateKey;

  @Autowired
  private ISysLoginTokenService sysLoginTokenService;

  @Override
  public LoginUserDTO checkLogin(String accessUrl, String hmac) throws ShopxException {
    log.info("checkLogin.begin");
    accessUrl = accessUrl.replaceAll("//","/");
    //解密hmac值
    LoginUserDTO loginUserDTO = null;
    SysUrlModel sysUrlModelParam = new SysUrlModel();
    sysUrlModelParam.setUrl(accessUrl);
    SysUrlModel url = urlService.selectOne(sysUrlModelParam);
    if (url != null) {
      log.info("url:{}存在，验证", accessUrl);
      if (CommonConstant.UrlFilterType.FILTER.equals(url.getUrlFilter())) {
        log.info("url为过滤地址，直接返回");
        return null;
      } else {
        log.info("url不为过滤地址");
        loginUserDTO = getEncLoginInfo(hmac);
        // 验证登录令牌
        boolean result = sysLoginTokenService.checkUserLogin(loginUserDTO.getUserId(), CommonConstant.UserType.MNG, loginUserDTO.getTokenId());
        if (!result) {
          throw new ShopxException(ResultCodeEnum.BUSI_TOKEN_INVALIDATE);
        }
        //验证是否有权限
        SysUserRoleModel sysUserRole = new SysUserRoleModel();
        sysUserRole.setUserId(loginUserDTO.getUserId());
        List<SysUserRoleModel> list = sysUserRoleDao.selectList(sysUserRole);
        if (list == null || list.size() <= 0) {//用户没有对应任何角色
          log.error("用户:{}没有对应任何角色.", loginUserDTO.getUserId());
          throw new ShopxException(ResultCodeEnum.USER_NOT_ROLE);
        }
        String[] roleCodes = new String[list.size()];
        for (int i = 0; i < list.size(); i++) {
          roleCodes[i] = list.get(i).getRoleCode();
        }
        if (!hasAccess(roleCodes, accessUrl)) {
          log.error("用户:{}，角色：{},没有该url：{}访问权限", loginUserDTO.getUserId(), roleCodes.toString(), accessUrl);
          throw new ShopxException(ResultCodeEnum.BUSI_NO_AUTH_ACCESS);
        }
      }
    } else {
      log.info("url:{}不存在，若登录则放行", accessUrl);
      loginUserDTO = getEncLoginInfo(hmac);
      boolean result = sysLoginTokenService.checkUserLogin(loginUserDTO.getUserId(), CommonConstant.UserType.MNG, loginUserDTO.getTokenId());
      if (!result) {
        throw new ShopxException(ResultCodeEnum.BUSI_TOKEN_INVALIDATE);
      }
    }
    return loginUserDTO;
  }

  /**
    * 解密获取令牌信息 格式（用户编号:令牌）
    * @author lituo
    * @date 1:45 PM 2021/12/6
    * @param	hmac
    * @return com.shopx.auth.dto.LoginUserDTO
    */
  private LoginUserDTO getEncLoginInfo(String hmac) throws ShopxException {
    // 开始解密
    String decStr = "";
    try {
      decStr = RSAUtils.privateDecrypt(hmac, RSAUtils.getPrivateKey(rsaPrivateKey));
    } catch (Exception e) {
      log.error("getEncLoginInfo.error:{}",e);
      throw new ShopxException(ResultCodeEnum.BUSI_SIGN_ERROR);
    }
    String userId = decStr.split(":")[0];
    String tokenId = decStr.split(":")[1];
    String cpId = decStr.split(":")[2];
    LoginUserDTO dto = new LoginUserDTO();
    dto.setUserId(userId);
    dto.setTokenId(tokenId);
    dto.setCpId(cpId);
    return dto;
  }

  /**
   * @description:验证角色是否有url访问权限
   *
   * @param roleCodes
   * @param url
   * @author:lituo
   * @date:2021-01-05 11:49 AM
   * @return:boolean
   */
  private boolean hasAccess(String[] roleCodes, String url) throws ShopxException {
    log.info("验证角色：{}是否具有url：{}访问权限", roleCodes, url);
    SysUrlModel sysUrlModel = new SysUrlModel();
    sysUrlModel.setRoleCodes(roleCodes);
    sysUrlModel.setUrl(url);
    int count = urlService.selectRoleHaveUrl(sysUrlModel);
    if (count == 0) {
      log.warn("角色：{}不具有url：{}访问权限", roleCodes, url);
      throw new ShopxException(ResultCodeEnum.BUSI_NO_AUTH_ACCESS);
    }
    return true;
  }
}
